package com.mediator.Mediator.impl;

import com.mediator.Aop.IEmptyPipeline;
import com.mediator.Aop.IPipeline;
import com.mediator.Handler.ICommandHandler;
import com.mediator.Handler.IEmptyCommandHandler;
import com.mediator.Mediator.IMediator;
import com.mediator.Request.IEmptyRequest;
import com.mediator.Request.INotification;
import com.mediator.Request.IRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
@Component
public class Mediator implements IMediator {
    @Autowired
    private  ApplicationContext context;

    public Mediator()
    {
    }
    @Override
    public <R> R Send(IRequest<R> values) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        if (values!=null)
        {
            var valuesClass=values.getClass();
            var parameter=valuesClass.getGenericInterfaces()[0];
            if (parameter instanceof ParameterizedType)
            {
                Class generaType=(Class) ((ParameterizedType) parameter).getActualTypeArguments()[0];
                var commandresolvableType=ResolvableType.forClassWithGenerics(ICommandHandler.class,valuesClass,generaType);
                var pipeLineresolvableType=ResolvableType.forClassWithGenerics(IPipeline.class,valuesClass,generaType);
                IPipeline pipe=null;
                if (pipeLineresolvableType!=null)
                {
                    var pipeLineprovider=context.getBeanProvider(pipeLineresolvableType);
                    if (pipeLineprovider!=null)
                    {
                        var object=pipeLineprovider.getIfAvailable();
                        pipe=object!=null?(IPipeline)object:null;
                    }
                }
                boolean bPipeIsNull=pipe==null?true:false;
                if (commandresolvableType!=null)
                {
                    var provider=context.getBeanProvider(commandresolvableType);
                    var handlerobject=provider.getIfAvailable();
                    ICommandHandler handler=handlerobject!=null?(ICommandHandler)handlerobject:null;
                    if (!bPipeIsNull)
                    {
                        pipe.BeforeForHandler(values);
                    }
                    if (handler!=null)
                    {
                        try {
                            R res=(R)handler.Handle(values);
                            if (!bPipeIsNull)
                            {
                                pipe.AfterForHandler(res);
                            }
                            return res;
                        }
                        catch (Exception ex)
                        {
                            if (!bPipeIsNull) {
                                pipe.HandlerException(ex);
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    @Override
    public <T> void Publish(INotification<T> notification)
    {

    }

    @Override
    public void Send(IEmptyRequest val)
    {
        if (val!=null)
        {
            var classObj=val.getClass();
            var commandresolvableType=ResolvableType.forClassWithGenerics(IEmptyCommandHandler.class,classObj);
            var pipeLineresolvableType=ResolvableType.forClassWithGenerics(IEmptyPipeline.class,classObj);
            IEmptyPipeline pipe=null;
            if (pipeLineresolvableType!=null)
            {
                var pipeLineprovider=context.getBeanProvider(pipeLineresolvableType);
                if (pipeLineprovider!=null)
                {
                    var object=pipeLineprovider.getIfAvailable();
                    pipe=object!=null?(IEmptyPipeline)object:null;
                }
            }
            boolean bPipeIsNull=pipe==null?true:false;
            if (commandresolvableType!=null)
            {
                var provider=context.getBeanProvider(commandresolvableType);
                var handlerobject=provider.getIfAvailable();
                IEmptyCommandHandler handler=handlerobject!=null?(IEmptyCommandHandler)handlerobject:null;
                if (handler!=null)
                {
                    try
                    {
                        if (!bPipeIsNull) {
                            pipe.BeforeForHandler(val);
                        }
                        handler.Handle(val);
                        if (!bPipeIsNull) {
                            pipe.AfterForHandler();
                        }
                    }
                    catch (Exception ex)
                    {
                        if (!bPipeIsNull) {
                            pipe.HandlerException(ex);
                        }
                    }
                }
            }
        }
    }
}
